package com.gep.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;

import org.apache.log4j.Logger;

public class Conversor {

	private static final Logger LOGGER = Logger.getLogger(Conversor.class);

	public static Object converter(Object objetoOrigem, String nomeClasseDestino) {
		Class<?> classeOrigem;
		Collection<Method> metodosGetClasseOrigem;

		Class<?> classeDestino;
		Collection<Method> metodosSetClasseDestino;

		Object objetoDestino;

		objetoDestino = null;
		classeOrigem = objetoOrigem.getClass();
		metodosGetClasseOrigem = obterMetodosGet(classeOrigem);
		try {
			classeDestino = Class.forName(nomeClasseDestino);
			metodosSetClasseDestino = obterMetodosSet(classeDestino);

			objetoDestino = classeDestino.newInstance();
			for (Method metodoGet : metodosGetClasseOrigem) {
				for (Method metodoSet : metodosSetClasseDestino) {
					if (objetoMetodosIguais(metodoGet, metodoSet)) {
						Class<?> classeReturn;
						Class<?>[] classesParameter;

						classeReturn = metodoGet.getReturnType();
						classesParameter = metodoSet.getParameterTypes();
						if (classesParameter.length == 1) {
							if (classeReturn.equals(classesParameter[0])) {
								try {
									Object valorReturn;

									valorReturn = metodoGet
											.invoke(objetoOrigem);
									metodoSet
											.invoke(objetoDestino, valorReturn);
								} catch (IllegalArgumentException e) {
									LOGGER.error(e.getStackTrace());
								} catch (IllegalAccessException e) {
									LOGGER.error(e.getStackTrace());
								} catch (InvocationTargetException e) {
									LOGGER.error(e.getStackTrace());
								}
							} else {
								if (classeReturn.getSuperclass().equals(
										Number.class)) {
									if (classesParameter[0].getSuperclass()
											.equals(Number.class)) {
										Object valorReturn;

										valorReturn = converterNumero(metodoGet
												.invoke(objetoOrigem),
												classesParameter[0]);
										metodoSet.invoke(objetoDestino,
												valorReturn);
									} else {
										if (classeReturn.equals(Long.class)) {
											Long tempo;

											tempo = (Long) metodoGet
													.invoke(objetoOrigem);
											if (classesParameter[0]
													.equals(Date.class)) {
												metodoSet.invoke(objetoDestino,
														new Date(tempo));
											}
										}
									}
								}
							}
						}
					} else if (objetoMetodosIguaisDTO(metodoGet, metodoSet)) {
						Class<?>[] classesParameter;

						classesParameter = metodoSet.getParameterTypes();
						if (classesParameter.length == 1) {
							try {
								Object valorDestino = null;
								
								Object valorOrigem = metodoGet
										.invoke(objetoOrigem);
								if(valorOrigem != null){
								 valorDestino = Conversor.converter(
										valorOrigem, classesParameter[0]
												.getName());
								}
								metodoSet.invoke(objetoDestino, valorDestino);

							} catch (IllegalArgumentException e) {
								LOGGER.error(e.getStackTrace());
							} catch (IllegalAccessException e) {
								LOGGER.error(e.getStackTrace());
							} catch (InvocationTargetException e) {
								LOGGER.error(e.getStackTrace());
							}

						}
					}
				}
			}

		} catch (ClassNotFoundException e) {
			LOGGER.error(e.getStackTrace());
		} catch (InstantiationException e) {
			LOGGER.error(e.getStackTrace());
		} catch (IllegalAccessException e) {
			LOGGER.error(e.getStackTrace());
		} catch (IllegalArgumentException e) {
			LOGGER.error(e.getStackTrace());
		} catch (InvocationTargetException e) {
			LOGGER.error(e.getStackTrace());
		}
		return objetoDestino;
	}

	private static Boolean objetoMetodosIguais(Method metodoGet,
			Method metodoSet) {
		String nomeMetodoGet;
		String nomeMetodoSet;

		nomeMetodoGet = metodoGet.getName().substring(3);
		nomeMetodoSet = metodoSet.getName().substring(3);
		return nomeMetodoGet.equals(nomeMetodoSet);
	}

	private static Boolean objetoMetodosIguaisDTO(Method metodoGet,
			Method metodoSet) {
		String nomeMetodoGet;
		String nomeMetodoSet;

		nomeMetodoGet = metodoGet.getName().substring(3);
		nomeMetodoSet = metodoSet.getName().substring(3);

		if (nomeMetodoGet.endsWith("DTO")) {
			nomeMetodoGet = nomeMetodoGet.replace("DTO", "");
		}
		if (nomeMetodoSet.endsWith("DTO")) {
			nomeMetodoSet = nomeMetodoSet.replace("DTO", "");
		}
		return nomeMetodoGet.equals(nomeMetodoSet);
	}

	private static Collection<Method> obterMetodosSet(Class<?> classe) {
		return obterMetodosIniciados(classe, "set");
	}

	private static Collection<Method> obterMetodosGet(Class<?> classe) {
		return obterMetodosIniciados(classe, "get");
	}

	private static Collection<Method> obterMetodosIniciados(Class<?> classe,
			String subString) {
		Collection<Method> metodos;
		Collection<Method> result;

		result = new LinkedList<Method>();
		metodos = Arrays.asList(classe.getMethods());
		for (Method metodo : metodos) {
			if (metodo.getName().indexOf(subString) == 0) {
				result.add(metodo);
			}
		}
		return result;
	}

	private static Number converterNumero(Object valor,
			Class<?> classeParametroMetodoSet) {
		Number valorFinal;
		Number valorNumerico;

		valorFinal = null;
		if (valor instanceof Number) {
			valorNumerico = (Number) valor;
			if (classeParametroMetodoSet.equals(Long.class)) {
				valorFinal = valorNumerico.longValue();
			}
			if (classeParametroMetodoSet.equals(Integer.class)) {
				valorFinal = valorNumerico.intValue();
			}
			if (classeParametroMetodoSet.equals(Short.class)) {
				valorFinal = valorNumerico.shortValue();
			}
			if (classeParametroMetodoSet.equals(Byte.class)) {
				valorFinal = valorNumerico.byteValue();
			}
		}
		return valorFinal;
	}

}